home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / HyperCuber 2.0 Source / CEnhancedWindow < prev    next >
Encoding:
Text File  |  1994-04-29  |  21.5 KB  |  618 lines  |  [TEXT/KAHL]

  1. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2. //| CEnhancedWindow.cp
  3. //|
  4. //| This file contains the implementation of an enhanced window.  This window
  5. //| is more aware of multiple screens that a normal window, and can place
  6. //| and zoom itself intelligently depending on the screen setup.
  7. //|___________________________________________________________________________
  8.  
  9. #include "CControlsWindow.h"
  10. #include "CHyperCuberPrefs.h"
  11.  
  12.  
  13.  
  14. //=============================== Procedure Prototypes ===============================\\
  15.  
  16. void get_window_rect(CWindow *window, Rect *window_rect);
  17. void set_window_rect(CWindow *window, Rect *window_rect);
  18.  
  19. pascal void CalcWindowAreaOnScreen(short depth, short deviceFlags, GDHandle targetDevice,
  20.                                     long userData);
  21. short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint,
  22.                             short idealOnScreenStartPoint, short idealOnScreenEndPoint,
  23.                             short screenEdge1, short screenEdge2);
  24.  
  25. //=============================== Globals ===============================\\
  26.  
  27. extern CHyperCuberPrefs *gPrefs;
  28.  
  29.  
  30.  
  31. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  32. //| CControlsWindow::IControlsWindow
  33. //|
  34. //| Purpose: Initialize the window
  35. //|
  36. //| Parameters: passed to superclass
  37. //|______________________________________________________________
  38.  
  39. void CControlsWindow::IControlsWindow(short WINDid, Boolean aFloating,
  40.                         CDesktop *anEnclosure, CDirector *aSupervisor, short dim)
  41. {
  42.  
  43.     inherited::IWindow(WINDid, aFloating, anEnclosure, aSupervisor);
  44.     
  45.     dimension = dim;
  46.  
  47. }    //==== CControlsWindow::IControlsWindow() ====\\
  48.  
  49.  
  50.  
  51. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  52. //| CControlsWindow::Drag
  53. //|
  54. //| Purpose: Draw the window
  55. //|
  56. //| Parameters: passed to superclass
  57. //|______________________________________________________________
  58.  
  59. void CControlsWindow::Drag(EventRecord *macEvent)
  60. {
  61.     
  62.     inherited::Drag(macEvent);
  63.  
  64. #if 0
  65.     Rect window_position;
  66.     get_window_rect(this, &window_position);                    //  Get new window position
  67.     
  68.     Point float_loc; 
  69.     float_loc.h = window_position.left;
  70.     float_loc.v = window_position.top;
  71.     SetShowFloatLoc(float_loc);                                    //  Set floating location
  72.  
  73.     gPrefs->prefs.controls_window_position[dimension] =
  74.                                                 window_position;//  Save new window position
  75. #endif
  76.  
  77. }    //==== CControlsWindow::Drag() ====\\
  78.  
  79.  
  80.  
  81. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  82. //| CControlsWindow::Move
  83. //|
  84. //| Purpose: Move the window
  85. //|
  86. //| Parameters: passed to superclass
  87. //|______________________________________________________________
  88.  
  89. void CControlsWindow::Move(short h, short v)
  90. {
  91.     
  92.     inherited::Move(h, v);
  93.     
  94. //    Rect window_position;
  95. //    get_window_rect(this, &window_position);                    //  Get new window position
  96.     
  97. //    gPrefs->prefs.controls_window_position[dimension] =
  98. //                                                window_position;//  Save new window position
  99.  
  100. }    //==== CControlsWindow::Move() ====\\
  101.  
  102.  
  103.  
  104. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  105. //| CControlsWindow::HideFloat
  106. //|
  107. //| Purpose: Hide the floating window
  108. //|
  109. //| Parameters: passed to superclass
  110. //|______________________________________________________________
  111.  
  112. void CControlsWindow::HideFloat(void)
  113. {
  114.  
  115.     Rect window_position;
  116.     get_window_rect(this, &window_position);                    //  Get window position
  117.     gPrefs->prefs.controls_window_position[dimension] =
  118.                                                 window_position;//  Save new window position
  119.     gPrefs->prefs.controls_window_visible[dimension] = FALSE;    //  Window is no longer visible
  120.     
  121.     inherited::HideFloat();                                        //  Hide the window    
  122.  
  123. }    //==== CControlsWindow::HideFloat() ====\\
  124.  
  125.  
  126.  
  127. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  128. //| CControlsWindow::ShowFloat
  129. //|
  130. //| Purpose: Show the floating window
  131. //|
  132. //| Parameters: passed to superclass
  133. //|______________________________________________________________
  134.  
  135. void CControlsWindow::ShowFloat(void)
  136. {
  137.  
  138.     Rect window_rect =
  139.             gPrefs->prefs.controls_window_position[dimension];    //  Get correct position
  140.  
  141.     hiding.h = window_rect.left;                                //  Show window at correct place
  142.     hiding.v = window_rect.top;
  143.  
  144.     inherited::ShowFloat();                                        //  Show the window
  145.  
  146.     set_window_rect(this, &window_rect);                        //  Move to correct position
  147.  
  148.     gPrefs->prefs.controls_window_visible[dimension] = TRUE;    //  Window is now visible
  149.  
  150. }    //==== CControlsWindow::Show() ====\\
  151.  
  152.  
  153.  
  154. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  155. //| CControlsWindow::Zoom
  156. //|
  157. //| Purpose: Zoom the window.  This code is from Develop magazine, issue 17.
  158. //|
  159. //| Parameters: passed to superclass
  160. //|__________________________________________________________________________
  161.  
  162. struct ZoomData {
  163.     GDHandle        screenWithLargestPartOfWindow;
  164.     unsigned long    largestArea;
  165.     Rect            windowBounds;
  166. };
  167. typedef struct ZoomData ZoomData, *ZoomDataPtr;
  168.  
  169. enum {
  170.     kNudgeSlop    =    4,
  171.     kIconSpace    =    64
  172. };
  173.  
  174. void CControlsWindow::Zoom(short zoomState)
  175. {
  176.  
  177.     ZoomData    zoomData;
  178.     Rect        newStandardRect;
  179.     Rect        scratchRect;
  180.     Rect        screenRect;
  181.     Rect        portRect;
  182.     Rect        contentRegionBoundingBox;
  183.     Rect        structureRegionBoundingBox;
  184.     Rect        deviceLoopRect;
  185.     GrafPtr        currentPort;
  186.     RgnHandle    scratchRegion;
  187.     RgnHandle    contentRegion;
  188.     RgnHandle    structureRegion;
  189.     GDHandle    mainDevice;
  190.     short        horizontalAmountOffScreen;
  191.     short        verticalAmountOffScreen;
  192.     short        windowFrameTopSize;
  193.     short        windowFrameLeftSize;
  194.     short        windowFrameRightSize;
  195.     short        windowFrameBottomSize;
  196.     
  197.  
  198.     GetPort(¤tPort);
  199.     Prepare();
  200.     contentRegion = ((CWindowPeek) GetMacPort())->contRgn;
  201.     structureRegion = ((CWindowPeek) GetMacPort())->strucRgn;
  202.     portRect = ((CWindowPeek) GetMacPort())->port.portRect;
  203.     contentRegionBoundingBox = (**contentRegion).rgnBBox;
  204.     structureRegionBoundingBox = (**structureRegion).rgnBBox;
  205.     
  206.     // Determine the size of the window frame
  207.     windowFrameTopSize = contentRegionBoundingBox.top - 
  208.                                     structureRegionBoundingBox.top;
  209.     windowFrameLeftSize = contentRegionBoundingBox.left - 
  210.                                     structureRegionBoundingBox.left;
  211.     windowFrameRightSize = structureRegionBoundingBox.right - 
  212.                                     contentRegionBoundingBox.right;
  213.     windowFrameBottomSize = structureRegionBoundingBox.bottom - 
  214.                                     contentRegionBoundingBox.bottom;
  215.                                     
  216.     // If the window is being zoomed into the standard state, calculate the best size
  217.     // to display the window’s information.
  218.     mainDevice = GetMainDevice();
  219.     if (zoomState == inZoomOut) {
  220.         zoomData.screenWithLargestPartOfWindow = mainDevice;
  221.         zoomData.largestArea = 0;
  222.     
  223.         // Usually, we would use the content region’s bounding box to determine the monitor
  224.         // with largest portion of the window’s area. However, if the entire content region
  225.         // of the window is not on any screen, the structure region should be used instead.
  226.         scratchRegion = NewRgn();
  227.         SectRgn(GetGrayRgn(), contentRegion, scratchRegion);
  228.         if (EmptyRgn(scratchRegion))
  229.             zoomData.windowBounds = structureRegionBoundingBox;
  230.         else
  231.             zoomData.windowBounds = contentRegionBoundingBox;
  232.     
  233.         // Use DeviceLoop to walk through all the active screens to find the one with the
  234.         // largest portion of the zoomed window
  235.         deviceLoopRect = zoomData.windowBounds;
  236.         GlobalToLocal((Point *)&deviceLoopRect);
  237.         GlobalToLocal((Point *)&deviceLoopRect.bottom);
  238.         RectRgn(scratchRegion, &deviceLoopRect);
  239.         DeviceLoop(scratchRegion, &CalcWindowAreaOnScreen, (long) &zoomData,
  240.                     (DeviceLoopFlags) singleDevices);
  241.         DisposeRgn(scratchRegion);
  242.         screenRect = (**(zoomData.screenWithLargestPartOfWindow)).gdRect;
  243.         
  244.         // If the monitor being zoomed to is the main monitor, change the top of the
  245.         // useable screen area to avoid putting the title bar underneath the menubar.
  246.         if (zoomData.screenWithLargestPartOfWindow == mainDevice)
  247.             screenRect.top += GetMBarHeight();
  248.             
  249.         // Go figure out the perfect size for the window as if we had an infinitely large
  250.         // screen
  251.         FindIdealWindowSize(&newStandardRect);
  252.         
  253.         // Anchor the new rectangle at the window’s current top left corner
  254.         OffsetRect(&newStandardRect, -newStandardRect.left, -newStandardRect.top);
  255.         OffsetRect(&newStandardRect, contentRegionBoundingBox.left,
  256.                     contentRegionBoundingBox.top);
  257.         
  258.         // newStandardRect is the ideal size for the content area. The window frame
  259.         // needs to be accounted for when we see if the window needs to be moved,
  260.         // or resized, so add in the dimensions of the window frame.
  261.         newStandardRect.top -= windowFrameTopSize;
  262.         newStandardRect.left -= windowFrameLeftSize;
  263.         newStandardRect.right += windowFrameRightSize;
  264.         newStandardRect.bottom += windowFrameBottomSize;
  265.         
  266.         // If the new rectangle falls off the edge of the screen, nudge it so that it’s just
  267.         // on the screen. CalculateOffsetAmount determines how much of the window is offscreen.
  268.         SectRect(&newStandardRect, &screenRect, &scratchRect);
  269.         if (!EqualRect(&newStandardRect, &scratchRect)) {
  270.             horizontalAmountOffScreen = CalculateOffsetAmount(newStandardRect.left,
  271.                                                                newStandardRect.right,
  272.                                                                scratchRect.left,
  273.                                                                scratchRect.right,
  274.                                                                screenRect.left,
  275.                                                                screenRect.right);
  276.             verticalAmountOffScreen = CalculateOffsetAmount(newStandardRect.top,
  277.                                                             newStandardRect.bottom,
  278.                                                             scratchRect.top,
  279.                                                             scratchRect.bottom,
  280.                                                             screenRect.top,
  281.                                                             screenRect.bottom);
  282.             OffsetRect(&newStandardRect, horizontalAmountOffScreen,
  283.                         verticalAmountOffScreen);
  284.         }
  285.     
  286.         // If we’re still falling off the edge of the screen, that means that the perfect
  287.         // size is larger than the screen, so we need to shrink down the standard size
  288.         SectRect(&newStandardRect, &screenRect, &scratchRect);
  289.         if (!EqualRect(&newStandardRect, &scratchRect)) {
  290.  
  291.         // First shrink the width of the window. If the window is wider than the screen
  292.         // it is zooming to, we can just pin the standard rectangle to the edges of the
  293.         // screen, leaving some slop. If the window is narrower than the screen, we know
  294.         // we just nudged it into position, so nothing needs to be done.
  295.             if ((newStandardRect.right - newStandardRect.left) >
  296.                 (screenRect.right - screenRect.left)) {
  297.                 newStandardRect.left = screenRect.left + kNudgeSlop;
  298.                 newStandardRect.right = screenRect.right - kNudgeSlop;
  299.  
  300.                 if ((zoomData.screenWithLargestPartOfWindow == mainDevice) &&
  301.                     (newStandardRect.right > (screenRect.right - kIconSpace)))
  302.                     newStandardRect.right = screenRect.right - kIconSpace;
  303.             }
  304.  
  305.             // Move in the top. Like the width of the window, nothing needs to be done unless
  306.             // the window is taller than the height of the screen.
  307.             if ((newStandardRect.bottom - newStandardRect.top) >
  308.                 (screenRect.bottom - screenRect.top)) {
  309.                 newStandardRect.top = screenRect.top + kNudgeSlop;
  310.                 newStandardRect.bottom = screenRect.bottom - kNudgeSlop;
  311.             }
  312.         }
  313.  
  314.         // We’ve got the best possible window position. Remove the
  315.         // frame, slam it into the WStateData record and let ZoomWindow
  316.         // take care of the rest.
  317.         newStandardRect.top += windowFrameTopSize;
  318.         newStandardRect.left += windowFrameLeftSize;
  319.         newStandardRect.right -= windowFrameRightSize;
  320.         newStandardRect.bottom -= windowFrameBottomSize;
  321.         (**((WStateDataHandle) ((CWindowPeek) GetMacPort())->dataHandle)).stdState = newStandardRect;
  322.         //  the above line sets the standard state
  323.     }
  324.     else
  325.         newStandardRect = (**((WStateDataHandle) ((CWindowPeek) GetMacPort())->dataHandle)).userState;
  326.         //  the above line puts the user state in newStandardRect
  327.         
  328.     // If the window is still anchored at the current location, then just resize it
  329.     if ((newStandardRect.left == contentRegionBoundingBox.left) &&
  330.         (newStandardRect.top == contentRegionBoundingBox.top)) {
  331.         OffsetRect(&newStandardRect, -newStandardRect.left, -newStandardRect.top);
  332.         ChangeSize(newStandardRect.right, newStandardRect.bottom);
  333.         
  334.     }
  335.     else {
  336.         scratchRegion = NewRgn();
  337.         GetClip(scratchRegion);
  338.         ClipRect(&portRect);
  339.         EraseRect(&portRect);
  340.         inherited::Zoom(zoomState);                //  Zoom, using superclass
  341.         SetClip(scratchRegion);
  342.         DisposeRgn(scratchRegion);
  343.     }
  344.     
  345.     SetPort(currentPort);
  346.  
  347. }    //==== CControlsWindow:: Zoom() ====\\
  348.  
  349.  
  350.  
  351. pascal void    CalcWindowAreaOnScreen(short depth, short deviceFlags, GDHandle targetDevice, long userData)
  352. {
  353.  
  354.     ZoomDataPtr    zoomData = (ZoomDataPtr) userData;
  355.     long        windowAreaOnScreen;
  356.     Rect        windowPortionOnScreen;
  357.     
  358.     // Find the rectangle that encloses the intersection of the window and this screen.
  359.     SectRect(&(zoomData->windowBounds), &((**targetDevice).gdRect), &windowPortionOnScreen);
  360.     
  361.     // Offset the rectangle so that it’s right and bottom are also it’s width and height.
  362.     OffsetRect(&windowPortionOnScreen, -windowPortionOnScreen.left, -windowPortionOnScreen.top);
  363.     
  364.     // Calculate the area of the portion of the window that’s on this screen.
  365.     windowAreaOnScreen = (long) windowPortionOnScreen.right * (long) windowPortionOnScreen.bottom;
  366.     
  367.     // If this is the largest portion of the window that has been encountered so far,
  368.     // remember this screen as the potential screen to zoom to.
  369.     if (windowAreaOnScreen > zoomData->largestArea) {
  370.         zoomData->largestArea = windowAreaOnScreen;
  371.         zoomData->screenWithLargestPartOfWindow = targetDevice;
  372.     }
  373. }
  374.  
  375. // Figure out how much we need to move the window to get it entirely on the monitor.  If
  376. // the window wouldn’t fit completely on the monitor anyway, don’t move it at all; we’ll
  377. // make it fit later on.
  378.  
  379. short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint, short idealOnScreenStartPoint,
  380.                             short idealOnScreenEndPoint, short screenEdge1, short screenEdge2)
  381. {
  382.     short    offsetAmount;
  383.  
  384.     // First check to see if the window fits on the screen in this dimension.
  385.     if ((idealStartPoint < screenEdge1) && (idealEndPoint > screenEdge2))
  386.         offsetAmount = 0;
  387.     else {
  388.     
  389.         // Find out how much of the window lies off this screen by subtracting the amount of the window
  390.         // that is on the screen from the size of the entire window in this dimension. If the window
  391.         // is completely offscreen, the offset amount is going to be the distance from the ideal
  392.         // starting point to the first edge of the screen.
  393.         if ((idealOnScreenStartPoint - idealOnScreenEndPoint) == 0) {
  394.             // See if the window is lying to the left or above the screen
  395.             if (idealEndPoint < screenEdge1)
  396.                 offsetAmount = screenEdge1 - idealStartPoint + kNudgeSlop;
  397.             else
  398.             // Otherwise, it’s below or to the right of the screen
  399.                 offsetAmount = screenEdge2 - idealEndPoint - kNudgeSlop;
  400.         }
  401.         else {
  402.             // Window is already partially or completely on the screen
  403.             offsetAmount = (idealEndPoint - idealStartPoint) -
  404.                             (idealOnScreenEndPoint - idealOnScreenStartPoint);
  405.     
  406.             // If we are offscreen a little, move the window in a few more pixels from the edge of the screen.
  407.             if (offsetAmount != 0)
  408.                 offsetAmount += kNudgeSlop;
  409.             
  410.             // Check to see which side of the screen the window was falling off of, so that it can be
  411.             // nudged in the opposite direction.
  412.             if (idealEndPoint > screenEdge2)
  413.                 offsetAmount = -offsetAmount;
  414.         }
  415.     }
  416.     
  417.     return offsetAmount;
  418. }
  419.  
  420.  
  421.  
  422. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  423. //| CControlsWindow::FindIdealWindowSize
  424. //|
  425. //| Purpose: Compute ideal size for this window
  426. //|
  427. //| Parameters: rect: received the ideal window size
  428. //|__________________________________________________________________________
  429.  
  430. void CControlsWindow::FindIdealWindowSize(Rect *rect)
  431. {
  432.  
  433.     rect->left = 0;
  434.     rect->right = 300;
  435.     rect->top = 0;
  436.     rect->bottom = 200;
  437.  
  438. }    //==== CControlsWindow::FindIdealWindowSize() ====\\
  439.  
  440.  
  441.  
  442. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  443. //| CControlsWindow::MakeWindowFullScreen
  444. //|
  445. //| Purpose: Resizes the window to fill the screen
  446. //|
  447. //| Parameters: none
  448. //|___________________________________________________________________________
  449.  
  450. void CControlsWindow::MakeWindowFullScreen(void)
  451. {
  452.     
  453.     Move(0, 0);                                            //  Move the window to the very top left.  Note that
  454.                                                         //   this moved the structure offscreen so only the
  455.                                                         //   contents is visible, and that even the top of
  456.                                                         //   the contents will be obscured unless the menu bar
  457.                                                         //   is hidden
  458.     
  459.     Rect main_monitor_bounds;
  460.     GDHandle graphics_device;
  461.     graphics_device = GetDeviceList ();                    //  Get the first (main) device in the list
  462.     main_monitor_bounds = (*graphics_device)->gdRect;    //  Get the main device bounds rect
  463.  
  464.     ChangeSize(main_monitor_bounds.right -                //  Resize the window to fill the screen
  465.                     main_monitor_bounds.left,
  466.                 main_monitor_bounds.bottom -
  467.                     main_monitor_bounds.top);
  468.  
  469. }    //==== CControlsWindow::MakeWindowFullScreen() ====\\
  470.  
  471.  
  472.  
  473. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  474. //| CControlsWindow::PlaceWindow
  475. //|
  476. //| Purpose: Place the window according to bounds.
  477. //|
  478. //| Parameters: bounds: the desired position of the window
  479. //|__________________________________________________________________________
  480.  
  481. void CControlsWindow::PlaceWindow(Rect *bounds)
  482. {
  483.     
  484.     Move(bounds->left, bounds->top);                //  Move the window
  485.     ChangeSize(bounds->right - bounds->left,        //  Resize the window
  486.                 bounds->bottom - bounds->top);
  487.  
  488. }    //==== CControlsWindow::PlaceWindow() ====\\
  489.  
  490.  
  491.  
  492. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  493. //| CControlsWindow::GetWindowRect
  494. //|
  495. //| Purpose: Get the size and position of a window
  496. //|
  497. //| Parameters: window_rect: receives the current window position
  498. //|___________________________________________________________________________
  499.  
  500. void CControlsWindow::GetWindowRect(Rect *window_rect)
  501. {
  502.  
  503.     Point upper_left;
  504.     upper_left.h = upper_left.v = 0;                            //  Find upper left corner
  505.     Prepare();
  506.     LocalToGlobal(&upper_left);
  507.  
  508.     LongRect window_interior;                                    //  Find height and width
  509.     GetInterior(&window_interior);
  510.     
  511.     window_rect->left = window_interior.left + upper_left.h;        //  Generate bounding rect
  512.     window_rect->right = window_interior.right + upper_left.h;
  513.     window_rect->top = window_interior.top + upper_left.v;
  514.     window_rect->bottom = window_interior.bottom + upper_left.v;
  515.     
  516. }    //==== CControlsWindow::GetWindowRect() ====\\
  517.  
  518.  
  519.  
  520. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  521. //| CControlsWindow::PlaceWindowWithVerify
  522. //|
  523. //| Purpose: Place the window according to bounds.  If this would result in
  524. //|          the window being placed offscreen, move it onscreen.
  525. //|
  526. //| Parameters: bounds: the desired position of the window
  527. //|__________________________________________________________________________
  528.  
  529. void CControlsWindow::PlaceWindowWithVerify(Rect *bounds)
  530. {
  531.  
  532. OffsetRect (bounds, -2000, -2000);            //  DEBUG
  533.  
  534.     Rect main_monitor_bounds;
  535.     GDHandle graphics_device;
  536.     graphics_device = GetDeviceList();                            //  Get the first (main) device in the list
  537.     main_monitor_bounds = (*graphics_device)->gdRect;            //  Save the main device bounds rect
  538.     
  539.     
  540.     short title_bar_height =
  541.         (*((WindowPeek) GetMacPort())->contRgn)->rgnBBox.top -
  542.         (*((WindowPeek) GetMacPort())->strucRgn)->rgnBBox.top;    //  Find the height of the title bar for the
  543.                                                                 //   window by finding the difference between
  544.                                                                 //   the content and structure regions.  Note:
  545.                                                                 //   this will fail for strange windows which
  546.                                                                 //   do not have a title bar at the top.
  547.     Rect title_bar_bounds;
  548.     title_bar_bounds.left = bounds->left;                        //  Find the title bar rect for new position
  549.     title_bar_bounds.right = bounds->right;
  550.     title_bar_bounds.top = bounds->top - title_bar_height;
  551.     title_bar_bounds.bottom = bounds->top;
  552.     
  553.     Boolean enough_intersection;
  554.     do                                                            //  Scan through all devices
  555.         {
  556.         Rect intersection;
  557.         Rect this_monitor_rect;
  558.         
  559.         this_monitor_rect = (*graphics_device)->gdRect;            //  Get the rect for this monitor
  560.  
  561.         if (graphics_device == GetMainDevice())                    //  Shrink menubar screen by size of menubar
  562.             this_monitor_rect.top += GetMBarHeight();
  563.  
  564.         SectRect (&title_bar_bounds, &this_monitor_rect,        //  If this device intersects the title bar
  565.                     &intersection);                                //   in a 4x4 block, we're okay.
  566.         enough_intersection =     
  567.                 (((intersection.bottom - intersection.top) >= 4) &&
  568.                 ((intersection.right - intersection.left) >= 4));
  569.  
  570.         graphics_device =                                        //  Next device
  571.                 (GDHandle) (*graphics_device)->gdNextGD;
  572.         }
  573.     while (graphics_device && (!enough_intersection));
  574.  
  575.     if (!enough_intersection)                                    //  This window is not draggable from any
  576.                                                                 //  monitor; move it to the main monitor.
  577.         {
  578.         
  579.         const short kSlopFactor = 4;
  580.  
  581.         short window_height = bounds->right - bounds->left;        //  Find size of window
  582.         short window_width = bounds->bottom - bounds->top;
  583.         short main_monitor_width = main_monitor_bounds.right -
  584.                                     main_monitor_bounds.left;    //  Find size of main monitor
  585.         short main_monitor_height =
  586.                                 main_monitor_bounds.bottom -
  587.                                     main_monitor_bounds.top;
  588.         
  589.         if (window_width > main_monitor_width)                    
  590.             window_width = main_monitor_width - 2*kSlopFactor;    //  Fit window to monitor, horizontally
  591.         
  592.         if (window_height > main_monitor_height)
  593.             window_height = main_monitor_height - 2*kSlopFactor;//  Fit window to monitor, vertically
  594.  
  595.         if (bounds->left > main_monitor_bounds.right)
  596.             OffsetRect(bounds, -(bounds->left -
  597.                         main_monitor_bounds.right +
  598.                             window_width + kSlopFactor), 0);    //  Nudge barely on screen, to left
  599.         
  600.         if (bounds->right < main_monitor_bounds.left)
  601.             OffsetRect(bounds, main_monitor_bounds.left -
  602.                         bounds->left + kSlopFactor,
  603.                         0);                                        //  Nudge barely on screen, to right
  604.  
  605.         if (bounds->bottom < main_monitor_bounds.top)
  606.             OffsetRect(bounds, 0, main_monitor_bounds.top -
  607.                         bounds->top + kSlopFactor);                //  Nudge barely on screen, down
  608.  
  609.         if (bounds->top > main_monitor_bounds.bottom)
  610.             OffsetRect(bounds, 0, -(bounds->top -
  611.                             main_monitor_bounds.bottom +
  612.                                 window_height + kSlopFactor));    //  Nudge barely on screen, up
  613.  
  614.         }
  615.  
  616.     PlaceWindow(bounds);                                        //  Place the window
  617.  
  618. }    //==== CControlsWindow::PlaceWindowWithVerify() ====\\